PAGE 118,123
TITLE BIOS2 ---- 11/15/85 BIOS INTERRUPT ROUTINES
.286C
.XLIST
INCLUDE DSEG.INC
INCLUDE POSTEQU.INC
.LIST
CODE	SEGMENT BYTE PUBLIC

	PUBLIC	PRINT_SCREEN_1
	PUBLIC	RTC_INT
	PUBLIC	TIME_OF_DAY_1
	PUBLIC	TIMER_INT_1

	EXTRN	CMOS_READ:NEAR		; READ CMOS LOCATION ROUTINE
	EXTRN	CMOS_WRITE:NEAR 	; WRITE CMOS LOCATION ROUTINE
	EXTRN	DDS:NEAR		; LOAD (DS) WITH DATA SEGMENT SELECTOR

;--- INT  1A H -- (TIME OF DAY) ------------------------------------------------
;	THIS BIOS ROUTINE ALLOWS THE CLOCKS TO BE SET OR READ		       :
;									       :
; PARAMETERS:								       :
;     (AH) = 00H  READ THE CURRENT SETTING AND RETURN WITH,		       :
;		       (CX) = HIGH PORTION OF COUNT			       :
;		       (DX) = LOW PORTION OF COUNT			       :
;		       (AL) = 0 TIMER HAS NOT PASSED 24 HOURS SINCE LAST READ  :
;			      1 IF ON ANOTHER DAY. (RESET TO ZERO AFTER READ)  :
;									       :
;     (AH) = 01H  SET THE CURRENT CLOCK USING,				       :
;		      (CX) = HIGH PORTION OF COUNT			       :
;		      (DX) = LOW PORTION OF COUNT.			       :
;									       :
;		NOTE: COUNTS OCCUR AT THE RATE OF 1193180/65536 COUNTS/SECOND  :
;			     (OR ABOUT 18.2 PER SECOND -- SEE EQUATES)	       :
;									       :
;     (AH) = 02H  READ THE REAL TIME CLOCK AND RETURN WITH,		       :
;		       (CH) = HOURS IN BCD (00-23)			       :
;		       (CL) = MINUTES IN BCD (00-59)			       :
;		       (DH) = SECONDS IN BCD (00-59)			       :
;		       (DL) = DAYLIGHT SAVINGS ENABLE (00-01).		       :
;									       :
;     (AH) = 03H  SET THE REAL TIME CLOCK USING,			       :
;		      (CH) = HOURS IN BCD (00-23)			       :
;		      (CL) = MINUTES IN BCD (00-59)			       :
;		      (DH) = SECONDS IN BCD (00-59)			       :
;		      (DL) = 01 IF DAYLIGHT SAVINGS ENABLE OPTION, ELSE 00.    :
;									       :
;		NOTE: (DL)= 00 IF DAYLIGHT SAVINGS TIME ENABLE IS NOT ENABLED. :
;		      (DL)= 01 ENABLES TWO SPECIAL UPDATES THE LAST SUNDAY IN  :
;		      APRIL   (1:59:59 --> 3:00:00 AM) AND THE LAST SUNDAY IN  :
;		      OCTOBER (1:59:59 --> 1:00:00 AM) THE FIRST TIME.	       :
;									       :
;     (AH) = 04H  READ THE DATE FROM THE REAL TIME CLOCK AND RETURN WITH,      :
;		       (CH) = CENTURY IN BCD (19 OR 20) 		       :
;		       (CL) = YEAR IN BCD (00-99)			       :
;		       (DH) = MONTH IN BCD (01-12)			       :
;		       (DL) = DAY IN BCD (01-31).			       :
;									       :
;     (AH) = 05H  SET THE DATE INTO THE REAL TIME CLOCK USING,		       :
;		      (CH) = CENTURY IN BCD (19 OR 20)			       :
;		      (CL) = YEAR IN BCD (00-99)			       :
;		      (DH) = MONTH IN BCD (01-12)			       :
;		      (DL) = DAY IN BCD (01-31).			       :
;									       :
;     (AH) = 06H  SET THE ALARM TO INTERRUPT AT SPECIFIED TIME, 	       :
;		      (CH) = HOURS IN BCD (00-23 (OR FFH))		       :
;		      (CL) = MINUTES IN BCD (00-59 (OR FFH))		       :
;		      (DH) = SECONDS IN BCD (00-59 (OR FFH)).		       :
;									       :
;     (AH) = 07H  RESET THE ALARM INTERRUPT FUNCTION.			       :
;									       :
; NOTES: FOR ALL RETURNS CY= 0 FOR SUCCESSFUL OPERATION.		       :
;	 FOR (AH)= 2, 4, 6 - CARRY FLAG SET IF REAL TIME CLOCK NOT OPERATING.  :
;	 FOR (AH)= 6 - CARRY FLAG SET IF ALARM ALREADY ENABLED. 	       :
;	 FOR THE ALARM FUNCTION (AH = 6) THE USER MUST SUPPLY A ROUTINE AND    :
;	  INTERCEPT THE CORRECT ADDRESS IN THE VECTOR TABLE FOR INTERRUPT 4AH. :
;	  USE 0FFH FOR ANY "DO NOT CARE" POSITION FOR INTERVAL INTERRUPTS.     :
;	 INTERRUPTS ARE DISABLED DURING DATA MODIFICATION.		       :
;	 AH & AL ARE RETURNED MODIFIED AND NOT DEFINED EXCEPT WHERE INDICATED. :
;-------------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

TIME_OF_DAY_1	PROC  FAR
	STI				; INTERRUPTS BACK ON
	CMP	AH,(RTC_TBE-RTC_TB)/2	; CHECK IF COMMAND IN VALID RANGE (0-7)
	CMC				; COMPLEMENT CARRY FOR ERROR EXIT
	JC	TIME_9			; EXIT WITH CARRY = 1 IF NOT VALID

	PUSH	DS			; SAVE USERS (DS) SEGMENT
	CALL	DDS			; GET DATA SEGMENT SELECTOR
	PUSH	SI			; SAVE WORK REGISTER
	SHR	AX,8			; CONVERT FUNCTION TO BYTE OFFSET
	ADD	AX,AX			; CONVERT FUNCTION TO WORD OFFSET (CY=0)
	MOV	SI,AX			; PLACE INTO ADDRESSING REGISTER
	CLI				; NO INTERRUPTS DURING TIME FUNCTIONS
	CALL	CS:[SI]+OFFSET RTC_TB	; VECTOR TO FUNCTION REQUESTED WITH CY=0
					;  RETURN WITH CARRY FLAG SET FOR RESULT
	STI				; INTERRUPTS BACK ON
	MOV	AH,0			; CLEAR (AH) TO ZERO
	POP	SI			; RECOVER USERS REGISTER
	POP	DS			; RECOVER USERS SEGMENT SELECTOR
TIME_9: 				; RETURN WITH CY= 0 IF NO ERROR
	RET	2

					;	ROUTINE VECTOR TABLE (AH)=
RTC_TB	DW	RTC_00			; 0 = READ CURRENT CLOCK COUNT
	DW	RTC_10			; 1 = SET CLOCK COUNT
	DW	RTC_20			; 2 = READ THE REAL TIME CLOCK TIME
	DW	RTC_30			; 3 = SET REAL TIME CLOCK TIME
	DW	RTC_40			; 4 = READ THE REAL TIME CLOCK DATE
	DW	RTC_50			; 5 = SET REAL TIME CLOCK DATE
	DW	RTC_60			; 6 = SET THE REAL TIME CLOCK ALARM
	DW	RTC_70			; 7 = RESET ALARM
RTC_TBE EQU	$

TIME_OF_DAY_1	ENDP
PAGE
RTC_00	PROC	NEAR			;	READ TIME COUNT
	MOV	AL,@TIMER_OFL		; GET THE OVERFLOW FLAG
	MOV	@TIMER_OFL,0		; AND THEN RESET THE OVERFLOW FLAG
	MOV	CX,@TIMER_HIGH		; GET COUNT OF TIME HIGH WORD
	MOV	DX,@TIMER_LOW		; GET COUNT OF TIME LOW WORD
	RET				; RETURN WITH NO CARRY

RTC_10: 				;	SET TIME COUNT
	MOV	@TIMER_LOW,DX		; SET TIME COUNT LOW WORD
	MOV	@TIMER_HIGH,CX		; SET THE TIME COUNT HIGH WORD
	MOV	@TIMER_OFL,0		; RESET OVERFLOW FLAG
	RET				; RETURN WITH NO CARRY

RTC_20: 				;	GET RTC TIME
	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	JC	RTC_29			; EXIT IF ERROR (CY= 1)

	MOV	AL,CMOS_SECONDS 	; SET ADDRESS OF SECONDS
	CALL	CMOS_READ		; GET SECONDS
	MOV	DH,AL			; SAVE
	MOV	AL,CMOS_REG_B		; ADDRESS ALARM REGISTER
	CALL	CMOS_READ		; READ CURRENT VALUE OF DSE BIT
	AND	AL,00000001B		; MASK FOR VALID DSE BIT
	MOV	DL,AL			; SET [DL] TO ZERO FOR NO DSE BIT
	MOV	AL,CMOS_MINUTES 	; SET ADDRESS OF MINUTES
	CALL	CMOS_READ		; GET MINUTES
	MOV	CL,AL			; SAVE
	MOV	AL,CMOS_HOURS		; SET ADDRESS OF HOURS
	CALL	CMOS_READ		; GET HOURS
	MOV	CH,AL			; SAVE
	CLC				; SET CY= 0
RTC_29:
	RET				; RETURN WITH RESULT IN CARRY FLAG

RTC_30: 				;	SET RTC TIME
	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_35			; GO AROUND IF CLOCK OPERATING
	CALL	RTC_STA 		; ELSE TRY INITIALIZING CLOCK
RTC_35:
	MOV	AH,DH			; GET TIME BYTE - SECONDS
	MOV	AL,CMOS_SECONDS 	; ADDRESS SECONDS
	CALL	CMOS_WRITE		; UPDATE SECONDS
	MOV	AH,CL			; GET TIME BYTE - MINUTES
	MOV	AL,CMOS_MINUTES 	; ADDRESS MINUTES
	CALL	CMOS_WRITE		; UPDATE MINUTES
	MOV	AH,CH			; GET TIME BYTE - HOURS
	MOV	AL,CMOS_HOURS		; ADDRESS HOURS
	CALL	CMOS_WRITE		; UPDATE ADDRESS
	MOV	AX,X*CMOS_REG_B 	; ADDRESS ALARM REGISTER
	CALL	CMOS_READ		; READ CURRENT TIME
	AND	AL,01100010B		; MASK FOR VALID BIT POSITIONS
	OR	AL,00000010B		; TURN ON 24 HOUR MODE
	AND	DL,00000001B		; USE ONLY THE DSE BIT
	OR	AL,DL			; GET DAY LIGHT SAVINGS TIME BIT (OSE)
	XCHG	AH,AL			; PLACE IN WORK REGISTER AND GET ADDRESS
	CALL	CMOS_WRITE		; SET NEW ALARM BITS
	CLC				; SET CY= 0
	RET				; RETURN WITH CY= 0

RTC_40: 				;	GET RTC DATE
	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	JC	RTC_49			; EXIT IF ERROR (CY= 1)

	MOV	AL,CMOS_DAY_MONTH	; ADDRESS DAY OF MONTH
	CALL	CMOS_READ		; READ DAY OF MONTH
	MOV	DL,AL			; SAVE
	MOV	AL,CMOS_MONTH		; ADDRESS MONTH
	CALL	CMOS_READ		; READ MONTH
	MOV	DH,AL			; SAVE
	MOV	AL,CMOS_YEAR		; ADDRESS YEAR
	CALL	CMOS_READ		; READ YEAR
	MOV	CL,AL			; SAVE
	MOV	AL,CMOS_CENTURY 	; ADDRESS CENTURY LOCATION
	CALL	CMOS_READ		; GET CENTURY BYTE
	MOV	CH,AL			; SAVE
	CLC				; SET CY=0
RTC_49:
	RET				; RETURN WITH RESULTS IN CARRY FLAG

RTC_50: 				;	SET RTC DATE
	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_55			; GO AROUND	IF NO ERROR
	CALL	RTC_STA 		; ELSE INITIALIZE CLOCK
RTC_55:
	MOV	AX,CMOS_DAY_WEEK	; ADDRESS OF DAY OF WEEK BYTE
	CALL	CMOS_WRITE		; LOAD ZEROS TO DAY OF WEEK
	MOV	AH,DL			; GET DAY OF MONTH BYTE
	MOV	AL,CMOS_DAY_MONTH	; ADDRESS DAY OF MONTH BYTE
	CALL	CMOS_WRITE		; WRITE OF DAY OF MONTH REGISTER
	MOV	AH,DH			; GET MONTH
	MOV	AL,CMOS_MONTH		; ADDRESS MONTH BYTE
	CALL	CMOS_WRITE		; WRITE MONTH REGISTER
	MOV	AH,CL			; GET YEAR BYTE
	MOV	AL,CMOS_YEAR		; ADDRESS YEAR REGISTER
	CALL	CMOS_WRITE		; WRITE YEAR REGISTER
	MOV	AH,CH			; GET CENTURY BYTE
	MOV	AL,CMOS_CENTURY 	; ADDRESS CENTURY BYTE
	CALL	CMOS_WRITE		; WRITE CENTURY LOCATION
	MOV	AX,X*CMOS_REG_B 	; ADDRESS ALARM REGISTER
	CALL	CMOS_READ		; READ WIRRENT SETTINGS
	AND	AL,07FH 		; CLEAR 'SET BIT'
	XCHG	AH,AL			; MOVE TO WORK REGISTER
	CALL	CMOS_WRITE		; AND START CLOCK UPDATING
	CLC				; SET CY= 0
	RET				; RETURN CY=0

RTC_60: 				;	SET RTC ALARM
	MOV	AL,CMOS_REG_B		; ADDRESS ALARM
	CALL	CMOS_READ		; READ ALARM REGISTER
	TEST	AL,20H			; CHECK FOR ALARM ALREADY ENABLED
	STC				; SET CARRY IN CASE OF ERROR
	JNZ	RTC_69			; ERROR EXIT IF ALARM SET

	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_65			; SKIP INITIALIZATION IF NO ERROR
	CALL	RTC_STA 		; ELSE INITIALIZE CLOCK
RTC_65:
	MOV	AH,DH			; GET SECONDS BYTE
	MOV	AL,CMOS_SEC_ALARM	; ADDRESS THE SECONDS ALARM REGISTER
	CALL	CMOS_WRITE		; INSERT SECONDS
	MOV	AH,CL			; GET MINUTES PARAMETER
	MOV	AL,CMOS_MIN_ALARM	; ADDRESS MINUTES ALARM REGISTER
	CALL	CMOS_WRITE		; INSERT MINUTES
	MOV	AH,CH			; GET HOURS PARAMETER
	MOV	AL,CMOS_HR_ALARM	; ADDRESS HOUR ALARM REGISTER
	CALL	CMOS_WRITE		; INSERT HOURS
	IN	AL,INTB01		; READ SECOND INTERRUPT MASK REGISTER
	AND	AL,0FEH 		; ENABLE ALARM TIMER BIT (CY= 0)
	OUT	INTB01,AL		; WRITE UPDATED MASK
	MOV	AX,X*CMOS_REG_B 	; ADDRESS ALARM REGISTER
	CALL	CMOS_READ		; READ CURRENT ALARM REGISTER
	AND	AL,07FH 		; ENSURE SET BIT TURNED OFF
	OR	AL,20H			; TURN ON ALARM ENABLE
	XCHG	AH,AL			; MOVE MASK TO OUTPUT REGISTER
	CALL	CMOS_WRITE		; WRITE NEW ALARM MASK
	CLC				; SET CY= 0
RTC_69:
	MOV	AX,0			; CLEAR AX REGISTER
	RET				; RETURN WITH RESULTS IN CARRY FLAC

RTC_70: 				;	RESET ALARM
	MOV	AX,X*CMOS_REG_B 	; ADDRESS ALARM REGISTER (TO BOTH AH,AL)
	CALL	CMOS_READ		; READ ALARM REGISTER
	AND	AL,57H			; TURN OFF ALARM ENABLE
	XCHG	AH,AL			; SAVE DATA AND RECOVER ADDRESS
	CALL	CMOS_WRITE		; RESTORE NEW VALUE
	CLC				; SET CY= 0
	RET				; RETURN WITH NO CARRY

RTC_00	ENDP

RTC_STA PROC	NEAR			;	INITIALIZE REAL TIME CLOCK
	MOV	AX,26H*H+CMOS_REG_A	; ADDRESS REGISTER A AND LOAD DATA MASK
	CALL	CMOS_WRITE		; INITIALIZE STATUS REGISTER A
	MOV	AX,82H*H+CMOS_REG_B	; SET "SET BIT" FOR CLOCK INITIALIZATION
	CALL	CMOS_WRITE		; AND 24 HOUR MODE TO REGISTER B
	MOV	AL,CMOS_REG_C		; ADDRESS REGISTER C
	CALL	CMOS_READ		; READ REGISTER C TO INITIALIZE
	MOV	AL,CMOS_REG_D		; ADDRESS REGISTER D
	CALL	CMOS_READ		; READ REGISTER D TO INITIALIZE
	RET

RTC_STA ENDP

UPD_IPR PROC	NEAR			;	WAIT TILL UPDATE NOT IN PROGRESS
	PUSH	CX			; SAVE CALLERS REGISTER
	MOV	CX,800			; SET TIMEOUT LOOP COUNT
UPD_10:
	MOV	AL,CMOS_REG_A		; ADDRESS STATUS REGISTER A
	CLI				; NO TIMER INTERRUPTS DURING UPDATES
	CALL	CMOS_READ		; READ UPDATE IN PROCESS FLAG
	TEST	AL,80H			; IF UIP BIT IS ON ( CANNOT READ TIME )
	JZ	UPD_90			; EXIT WITH CY= 0 IF CAN READ CLOCK NOW
	STI				; ALLOW INTERRUPTS WHILE WAITING
	LOOP	UPD_10			; LOOP TILL READY OR TIMEOUT
	XOR	AX,AX			; CLEAR RESULTS IF ERROR
	STC				; SET CARRY FOR ERROR
UPD_90:
	POP	CX			; RESTORE CALLERS REGISTER
	CLI				; INTERRUPTS OFF DURING SET
	RET				; RETURN WITH CY FLAG SET

UPD_IPR ENDP
PAGE
;--- HARDWARE INT  70 H -- ( IRQ LEVEL	8 ) ------------------------------------
; ALARM INTERRUPT HANDLER (RTC) 					       :
;	THIS ROUTINE HANDLES THE PERIODIC AND ALARM INTERRUPTS FROM THE CMOS   :
;	TIMER.	INPUT FREQUENCY IS 1.024 KHZ OR APPROXIMATELY 1024 INTERRUPTS  :
;	EVERY SECOND FOR THE PERIODIC INTERRUPT.  FOR THE ALARM FUNCTION,      :
;	THE INTERRUPT WILL OCCUR AT THE DESIGNATED TIME.		       :
;									       :
;	INTERRUPTS ARE ENABLED WHEN THE EVENT OR ALARM FUNCTION IS ACTIVATED.  :
;	FOR THE EVENT INTERRUPT, THE HANDLER WILL DECREMENT THE WAIT COUNTER   :
;	AND WHEN IT EXPIRES WILL SET THE DESIGNATED LOCATION TO 80H.  FOR      :
;	THE ALARM INTERRUPT. THE USER MUST PROVIDE A ROUTINE TO INTERCEPT      :
;	THE CORRECT ADDRESS FROM THE VECTOR TABLE INVOKED BY INTERRUPT 4AH     :
;	PRIOR TO SETTING THE REAL TIME CLOCK ALARM (INT 1AH, AH= 06H).	       :
;-------------------------------------------------------------------------------

RTC_INT PROC	FAR			;	ALARM INTERRUPT
	PUSH	DS			; LEAVE INTERRUPTS DISABLED
	PUSH	AX			; SAVE REGISTERS
	PUSH	DI

RTC_I_1:				;	CHECK FOR SECOND INTERRUPT
	MOV	AX,(CMOS_REG_B+NMI)*H+CMOS_REG_C+NMI ; ALARM AND STATUS
	OUT	CMOS_PORT,AL		; WRITE ALARM FLAG MASK ADDRESS
	NOP				; I/O DELAY
	IN	AL,CMOS_DATA		; READ AND RESET INTERRUPT REQUEST FLAGS
	TEST	AL,01100000B		; CHECK FOR EITHER INTERRUPT PENDING
	JZ	RTC_I_9 		; EXIT IF NOT A VALID RTC INTERRUPT

	XCHG	AH,AL			; SAVE FLAGS AND GET ENABLE ADDRESS
	OUT	CMOS_PORT,AL		; WRITE ALARM ENABLE MASK ADDRESS
	NOP				; I/O DELAY
	IN	AL,CMOS_DATA		; READ CURRENT ALARM ENABLE MASK
	AND	AL,AH			; ALLOW ONLY SOURCES THAT ARE ENABLED
	TEST	AL,01000000B		; CHECK FOR PERIODIC INTERRUPT
	JZ	RTC_I_5 		; SKIP IF NOT A PERIODIC INTERRUPT

;-----	DECREMENT WAIT COUNT BY INTERRUPT INTERVAL

	CALL	DDS			; ESTABLISH DATA SEGMENT ADDRESSABILITY
	SUB	@RTC_LOW,0976		; DECREMENT COUNT LOW BY 1/1024
	SBB	@RTC_HIGH,0		; ADJUST HIGH WORD FOR LOW WORD BORROW
	JNC	RTC_I_5 		; SKIP TILL 32 BIT WORD LESS THAN ZERO

;-----	TURN OFF PERIODIC INTERRUPT ENABLE

	PUSH	AX			;	  SAVE INTERRUPT FLAG MASK
	MOV	AX,X*(CMOS_REG_B+NMI)	; INTERRUPT ENABLE REGISTER
	OUT	CMOS_PORT,AL		; WRITE ADDRESS TO CMOS CLOCK
	NOP				; I/O DELAY
	IN	AL,CMOS_DATA		; READ CURRENT ENABLES
	AND	AL,0BFH 		; TURN OFF PIE
	XCHG	AL,AH			; GET CMOS ADDRESS AND SAVE VALUE
	OUT	CMOS_PORT,AL		; ADDRESS REGISTER B
	XCHG	AL,AH			; GET NEW INTERRUPT ENABLE MASK
	OUT	CMOS_DATA,AL		; SET MASK IN INTERRUPT ENABLE REGISTER
	MOV	@RTC_WAIT_FLAG,0	; SET FUNCTION ACTIVE FLAG OFF
	LDS	DI,DWORD PTR @USER_FLAG ; SET UP (DS:DI) TO POINT TO USER FLAG
	MOV	BYTE PTR [DI],80H	; TURN ON USERS FLAG
	POP	AX			; GET INTERRUPT SOURCE BACK
RTC_I_5:
	TEST	AL,00100000B		; TEST FOR ALARM INTERRUPT
	JZ	RTC_I_7 		; SKIP USER INTERRUPT CALL IF NOT ALARM

	MOV	AL,CMOS_REG_D		; POINT TO DEFAULT READ ONLY REGISTER
	OUT	CMOS_PORT,AL		; ENABLE NMI AND CMOS ADDRESS TO DEFAULT
	STI				; INTERRUPTS BACK ON NOW
	PUSH	DX
	INT	4AH			; TRANSFER TO USER ROUTINE
	POP	DX
	CLI				; BLOCK INTERRUPT FOR RETRY
RTC_I_7:				; RESTART ROUTINE TO HANDLE DELAYED
	JMP	RTC_I_1 		;  ENTRY AND SECOND EVENT BEFORE DONE


RTC_I_9:				;	  EXIT - NO PENDING INTERRUPTS
	MOV	AL,CMOS_REG_D		; POINT TO DEFAULT READ ONLY REGISTER
	OUT	CMOS_PORT,AL		; ENABLE NMI AND CMOS ADDRESS TO DEFAULT
	MOV	AL,EOI			; END OF INTERRUPT MASK TO 8259 - 2
	OUT	INTB00,AL		; TO 8259 - 2
	OUT	INTA00,AL		; TO 8259 - 1
	POP	DI			; RESTORE REGISTERS
	POP	AX
	POP	DS
	IRET				; END OF INTERRUPT

RTC_INT ENDP
PAGE
;--- INT  05 H -----------------------------------------------------------------
; PRINT_SCREEN								       :
;	THIS LOGIC WILL BE INVOKED BY INTERRUPT 05H TO PRINT THE SCREEN.       :
;	THE CURSOR POSITION AT THE TIME THIS ROUTINE IS INVOKED WILL BE        :
;	SAVED AND RESTORED UPON COMPLETION.  THE ROUTINE IS INTENDED TO        :
;	RUN WITH INTERRUPTS ENABLED.   IF A SUBSEQUENT PRINT SCREEN KEY        :
;	IS DEPRESSED WHILE THIS ROUTINE IS PRINTING IT WILL BE IGNORED.        :
;	THE BASE PRINTERS STATUS IS CHECKED FOR NOT BUSY AND NOT OUT OF        :
;	PAPER.	AN INITIAL STATUS ERROR WILL ABEND THE PRINT REQUEST.	       :
;	ADDRESS  0050:0000  CONTAINS THE STATUS OF THE PRINT SCREEN:	       :
;									       :
;	50:0	= 0	PRINT SCREEN HAS NOT BEEN CALLED OR UPON RETURN        :
;			 FROM A CALL THIS INDICATES A SUCCESSFUL OPERATION.    :
;		= 1	PRINT SCREEN IS IN PROGRESS - IGNORE THIS REQUEST.     :
;		= 255	ERROR ENCOUNTERED DURING PRINTING.		       :
;-------------------------------------------------------------------------------

PRINT_SCREEN_1	PROC  FAR
					; DELAY INTERRUPT ENABLE TILL FLAG SET
	PUSH	DS
	PUSH	AX			; SAVE WORK REGISTERS
	PUSH	BX
	PUSH	CX
	PUSH	DX			; USE 0040:0100 FOR STATUS AREA STORAGE
	CALL	DDS			; GET STATUS_BYTE DATA SEGMENT
	CMP	@STATUS_BYTE,1		; SEE IF PRINT ALREADY IN PROGRESS
	JE	PRI90			; EXIT IF PRINT ALREADY IN PROGRESS
	MOV	@STATUS_BYTE,1		; INDICATE PRINT NOW IN PROGRESS
	STI				; MUST RUN WITH INTERRUPTS ENABLED
	MOV	AH,0FH			; WILL REQUEST THE CURRENT SCREEN MODE
	INT	10H			;	(AL)= MODE
					;	(AH)= NUMBER COLUMNS/LINE
					;	(BH)= VISUAL PAGE
	MOV	CL,AH			; WILL MAKE USE OF (CX) REGISTER TO
	MOV	CH,@ROWS		;  CONTROL ROWS ON SCREEN & COLUMNS
	INC	CH			; ADJUST ROWS ON DISPLAY COUNT
					;	(CL)= NUMBER COLUMNS/LINE
					;	(CH)= NUMBER OF ROWS ON DISPLAY
	;----------------------------------------------------------------
	;	AT THIS POINT WE KNOW THE COLUMNS/LINE COUNT IS IN (CL) :
	;	AND THE NUMBER OF ROWS ON THE DISPLAY IS IN (CH).	:
	;	THE PAGE IF APPLICABLE IS IN (BH).  THE STACK HAS	:
	;	(DS),(AX),(BX),(CX),(DX) PUSHED.			:
	;----------------------------------------------------------------
	XOR	DX,DX			; FIRST PRINTER
	MOV	AH,02H			; SET PRINTER STATUS REQUEST COMMAND
	INT	17H			; REQUEST CURRENT PRINTER STATUS
	XOR	AH,080H 		; CHECK FOR PRINTER BUSY (NOT CONNECTED)
	TEST	AH,0A0H 		;  OR OUT OF PAPER
	JNZ	PRI80			; ERROR EXIT IF PRINTER STATUS ERROR

	CALL	CRLF			; CARRIAGE RETURN LINE FEED TO PRINTER

	PUSH	CX			; SAVE SCREEN BOUNDS
	MOV	AH,03H			; NOW READ THE CURRENT CURSOR POSITION
	INT	10H			; AND RESTORE AT END OF ROUTINE
	POP	CX			; RECALL SCREEN BOUNDS
	PUSH	DX			; PRESERVE THE ORIGINAL POSITION
	XOR	DX,DX			; INITIAL CURSOR (0,0) AND FIRST PRINTER
	;----------------------------------------------------------------
	;	THIS LOOP IS TO READ EACH CURSOR POSITION FROM THE	:
	;	SCREEN AND PRINT IT.  (BH)= VISUAL PAGE  (CH)= ROWS	:
	;----------------------------------------------------------------
PRI10:
	MOV	AH,02H			; INDICATE CURSOR SET REQUEST
	INT	10H			; NEW CURSOR POSITION ESTABLISHED
	MOV	AH,08H			; INDICATE READ CHARACTER FROM DISPLAY
	INT	10H			; CHARACTER NOW IN (AL)
	OR	AL,AL			; SEE IF VALID CHAR
	JNZ	PRI20			; JUMP IF VALID CHAR
	MOV	AL,' '                  ; ELSE MAKE IT A BLANK
PRI20:
	PUSH	DX			; SAVE CURSOR POSITION
	XOR	DX,DX			; INDICATE FIRST PRINTER (DX= 0)
	XOR	AH,AH			; INDICATE PRINT CHARACTER IN (AL)
	INT	17H			; PRINT THE CHARACTER
	POP	DX			; RECALL CURSOR POSITION
	TEST	AH,29H			; TEST FOR PRINTER ERROR
	JNZ	PRI70			; EXIT IF ERROR DETECTED
	INC	DL			; ADVANCE TO NEXT COLUMN
	CMP	CL,DL			; SEE IF AT END OF LINE
	JNZ	PRI10			; IF NOT LOOP FOR NEXT COLUMN
	XOR	DL,DL			; BACK TO COLUMN 0
	MOV	AH,DL			; (AH)=0
	PUSH	DX			; SAVE NEW CURSOR POSITION
	CALL	CRLF			; LINE FEED CARRIAGE RETURN
	POP	DX			; RECALL CURSOR POSITION
	INC	DH			; ADVANCE TO NEXT LINE
	CMP	CH,DH			; FINISHED?
	JNZ	PRI10			; IF NOT LOOP FOR NEXT LINE

	POP	DX			; GET CURSOR POSITION
	MOV	AH,02H			; INDICATE REQUEST CURSOR SET
	INT	10H			; CURSOR POSITION RESTORED
	CLI				; BLOCK INTERRUPTS TILL STACK CLEARED
	MOV	@STATUS_BYTE,0		; MOVE OK RESULTS FLAG TO STATUS_BYTE
	JMP	SHORT PRI90		; EXIT PRINTER ROUTINE

PRI70:					; ERROR EXIT
	POP	DX			; GET CURSOR POSITION
	MOV	AH,02H			; INDICATE REQUEST CURSOR SET
	INT	10H			; CURSOR POSITION RESTORED
PRI80:
	CLI				; BLOCK INTERRUPTS TILL STACK CLEARED
	MOV	@STATUS_BYTE,0FFH	; SET ERROR FLAG
PRI90:
	POP	DX			; EXIT ROUTINE
	POP	CX			; RESTORE ALL THE REGISTERS USED
	POP	BX
	POP	AX
	POP	DS
	IRET				; RETURN WITH INITIAL INTERRUPT MASK
PRINT_SCREEN_1	ENDP

;-----	CARRIAGE RETURN, LINE FEED SUBROUTINE

CRLF	PROC	NEAR
					;	SEND CR,LF TO FIRST PRINTER
	XOR	DX,DX			; ASSUME FIRST PRINTER (DX= 0)
	MOV	AX,CR			; GET THE PRINT CHARACTER COMMAND AND
	INT	17H			;   THE CARRIAGE RETURN CHARACTER
	MOV	AX,LF			; NOW GET THE LINE FEED AND
	INT	17H			;   SEND IT TO THE BIOS PRINTER ROUTINE
	RET
CRLF	ENDP



;-- HARDWARE INT  08 H - ( IRQ LEVEL 0 ) ---------------------------------------
;	THIS ROUTINE HANDLES THE TIMER INTERRUPT FROM FROM CHANNEL 0 OF        :
;	THE 8254 TIMER.  INPUT FREQUENCY IS 1.19318 MHZ AND THE DIVISOR        :
;	IS 65536, RESULTING IN APPROXIMATELY 18.2 INTERRUPTS EVERY SECOND.     :
;									       :
;	THE INTERRUPT HANDLER MAINTAINS A COUNT (40:6C) OF INTERRUPTS SINCE    :
;	POWER ON TIME, WHICH MAY BE USED TO ESTABLISH TIME OF DAY.	       :
;	THE INTERRUPT HANDLER ALSO DECREMENTS THE MOTOR CONTROL COUNT (40:40)  :
;	OF THE DISKETTE, AND WHEN IT EXPIRES, WILL TURN OFF THE 	       :
;	DISKETTE MOTOR(s), AND RESET THE MOTOR RUNNING FLAGS.		       :
;	THE INTERRUPT HANDLER WILL ALSO INVOKE A USER ROUTINE THROUGH	       :
;	INTERRUPT 1CH AT EVERY TIME TICK.  THE USER MUST CODE A 	       :
;	ROUTINE AND PLACE THE CORRECT ADDRESS IN THE VECTOR TABLE.	       :
;-------------------------------------------------------------------------------

TIMER_INT_1	PROC  FAR
	STI				; INTERRUPTS BACK ON
	PUSH	DS
	PUSH	AX
	PUSH	DX			; SAVE MACHINE STATE
	CALL	DDS			; ESTABLISH ADDRESSABILITY
	INC	@TIMER_LOW		; INCREMENT TIME
	JNZ	T4			; GO TO TEST_DAY
	INC	@TIMER_HIGH		; INCREMENT HIGH WORD OF TIME
T4:					;	TEST_DAY
	CMP	@TIMER_HIGH,018H	; TEST FOR COUNT EQUALING 24 HOURS
	JNZ	T5			; GO TO DISKETTE_CTL
	CMP	@TIMER_LOW,0B0H
	JNZ	T5			; GO TO DISKETTE_CTL

;-----	TIMER HAS GONE 24 HOURS

	SUB	AX,AX
	MOV	@TIMER_HIGH,AX
	MOV	@TIMER_LOW,AX
	MOV	@TIMER_OFL,1

;-----	TEST FOR DISKETTE TIME OUT

T5:
	DEC	@MOTOR_COUNT		; DECREMENT DISKETTE MOTOR CONTROL
	JNZ	T6			; RETURN IF COUNT NOT OUT
	AND	@MOTOR_STATUS,0F0H	; TURN OFF MOTOR RUNNING BITS
	MOV	AL,0CH
	MOV	DX,03F2H		; FDC CTL PORT
	OUT	DX,AL			; TURN OFF THE MOTOR

T6:					; TIMER TICK INTERRUPT
	INT	1CH			; TRANSFER CONTROL TO A USER ROUTINE

	POP	DX			; RESTORE (DX)
	MOV	AL,EOI			; GET END OF INTERRUPT MASK
	CLI				; DISABLE INTERRUPTS TILL STACK CLEARED
	OUT	INTA00,AL		; END OF INTERRUPT TO 8259 - 1
	POP	AX
	POP	DS			; RESET MACHINE STATE
	IRET				; RETURN FROM INTERRUPT

TIMER_INT_1	ENDP

CODE	ENDS
	END
